package triIndex.btree;

import transaction.Transaction;
import triDataStruct.*;
import triStorage.*;
import triFileSystem.*;

public class NodeFactory extends MemoryBuffer{

	TriMMPFile mmpfile;
	
	//int maxNodeId;
	
	public NodeFactory(int bufferSize, int pageSize, TriMMPFile mmpfile) {
		super(bufferSize);
		this.mmpfile = mmpfile;
	}
	
	public void init(int maxNodeId) {
		//this.maxNodeId = maxNodeId;
	}
	
	public void dispose() {
		mmpfile.close();
	}
	
	public BNode createNewBranch(int order, Transaction tx) {
		int pageId = mmpfile.allocNewPage();
		int index = this.get(pageId, new BNodeArg(BNode.BRANCH, order, -1, true), tx);
		return (BNode)buffer[index];
	}

	public BNode createNewLeaf(int order, int nextNodeId, Transaction tx) {
		int pageId = mmpfile.allocNewPage();
		int index = this.get(pageId, new BNodeArg(BNode.LEAF, order, nextNodeId, true), tx);
		return (BNode)buffer[index];
	}
	
	public BNode getNode(int nodeId, int order, Transaction tx) {
		int index = this.get(nodeId, new BNodeArg(BNode.LEAF, order, -1, false), tx);
		return (BNode)buffer[index];
	}
	
	public void save(BNode node, Transaction tx) {
		if (node == null)
			return;
		synchronized (node) {
			if (node.index >= 0 && buffer[node.index] == node) {
				unPin(node.index);
				flushObject(node.index, tx);
			}
		}
	}
	
	public void unPin(BNode node) {
		if (node == null)
			return;
		synchronized (node) {
			if (node.index >= 0 && buffer[node.index] == node) {
				unPin(node.index);
			}
		}
	}

	public void flushToDisk(Transaction tx) {
		for (int i = 0; i < buffer.length; ++i) {
			if (buffer[i] != null)
				synchronized (buffer[i]) {
					flushObject(i, tx);
				}
		}
	}
	
	@Override
	protected BufferObject createEmptyObject(int index, Transaction tx) {
		return new BNode(index);
	}

	@Override
	protected void loadObject(int key, Object o, int index, Transaction tx) {
		BNodeArg arg = (BNodeArg)o;
		BNode node =(BNode)buffer[index];
		
		//System.out.println("****** flush out " + node.getKey() + " with " + key + " " + pinCnt[index]);
		//System.out.println(pinCnt[]);
		//System.out.println(">>>>>loading....");
		//System.out.println(">>>>> " + (arg.type == BNode.LEAF) + " " + key + " " + arg.create);
		
		node.reset(arg.type == BNode.LEAF, arg.order, key, arg.nextNodeId, this);
		if (!arg.create) {
			IReader reader = new PageReader(key, mmpfile);
			node.load(reader);
			reader.dispose();
		}
		
		buffer[index] = node;
	}

	@Override
	protected void flushObject(int index, Transaction tx) {
		BNode node = (BNode)buffer[index];
		IWriter writer = new PageWriter(node.getKey(), mmpfile);
		node.flush(writer, tx);
		
		writer.dispose();
	}


}

class BNodeArg {
	
	public int type;
	public int order;
	public int nextNodeId;
	
	public boolean create;
	
	BNodeArg(int type, int order, int nextNodeId, boolean create) {
		this.type = type;
		this.order = order;
		this.nextNodeId = nextNodeId;
		this.create = create;
	}
}
